﻿using System;
using Legal.Truffer;

namespace TrufferUser
{
    /*
    1.请用最接近C的C#
    2.少用C#的库函数,比如List 尽量只使用System;System.Math;System.IO
    3.函数名命名方式,全小写,不简写(除了一些一目了然的可以简写:atan()这样的),加下划线分割,如:is_vector()
    4.命名空间使用:namespace TrufferUser{} 类名使用:public static partial class we{}
    */
    public static partial class we
    {
        //编写范例
        /// <summary>
        /// 矩阵幂
        /// </summary>
        /// <param name="X">1个m阶方阵</param>
        /// <param name="n">方阵的幂</param>
        /// <returns>X的n次幂的结果</returns>
        public static Matrix matrix_power(Matrix X, int n)
        {
            //本函数使用了Truffer函数库中的矩阵求逆函数ex.inverse()

            //如果不是方阵，将返回被传入的矩阵，不做任何修改。
            //这是应对错误的简单方法。
            if (X.is_square_matrix() != true)
            { return X; }

            //以下的代码专门用于处理方阵。
            //以下代码不会产生不是方阵的矩阵。

            //如果是负数幂，那么需要将矩阵求逆，然后将幂设定为矩阵的绝对值
            if (n < 0)
            { return matrix_power(ex.inverse(X), n * (-1)); }

            //如果是0次幂，就返回一个单位矩阵。由于是方阵，可以用矩阵的行数来确定这个单位矩阵的行和列。
            else if (n == 0)
            { return ex.eye(X.Rows); }

            //如果是1次幂，返回被传入的矩阵，不做任何修改
            else if (n == 1)
            { return X; }

            //以下是计算的关键部分，我利用平方来进行化简。
            //如果是 矩阵A的22次幂 ，我会将其分解成  A的16次幂*A的4次幂*A的2次幂
            //也就是说，我将 幂的值 拆解成 由2的幂组成 的和

            //比如计算A的16次幂，我们不需要进行16次乘法。
            //我们可以计算B = A*A，然后计算B的8次幂。
            //然后可以计算C = B*B，然后计算C的4次幂。
            //然后可以计算D = C*C，然后计算D的2次幂。
            //最后就是E = D*D，返回E的1次幂。

            else
            {
                int i = 2;
                for (i = 2; i <= n; i++)
                {
                    i = i * 2;
                }
                i = i / 2;

                Matrix P = X * X;

                //采用尾递归的形式来进行递归

                return matrix_power(P, i / 2) * matrix_power(X, n - i);
            }
        }
    }
}